#!/bin/ash

. /etc/initrd.defaults

backup() {
	echo -ne "\033[0G\033[0K"
}

parse_opt() {
	case "$1" in
		*\=*)
			echo "$1" | cut -d= -f2-
		;;
	esac
}

modules_load() {
	for module in $*
	do
		echo ${module} >> /etc/modules/extra_load
	done

	modules_scan extra_load
}

modules_scan() {
	local MODS
	[ -d "/etc/modules/${1}" ] || touch /etc/modules/${1}

	[ -f "/etc/modules/${1}" ] && MODS=`cat /etc/modules/${1}`
	for x in ${MODS}
	do
		MLOAD=`echo ${MLIST} | sed -e "s/.*${x}.*/${x}/"`
		if [ "${MLOAD}" = "${x}" ] # Only module to no-load
		then
			echo -e "${BOLD}   ::${NORMAL} Skipping ${x}..."
		elif [ "${MLOAD}" = "${MLIST}" ] # == No change == No specified no-load
		then
			[ -n "${DEBUG}" ] && echo -ne "${BOLD}   ::${NORMAL} Checking for ${x}..."
			# find -name does not work since the return status is always zero
			if find /lib/modules/${KV} | grep /"${x}${KSUFF}" >/dev/null 2>&1
			then
				echo -ne "${BOLD}   ::${NORMAL} Scanning for ${x}..."
				modprobe ${x} -n
				backup
				echo -ne "${NORMAL}"
			fi
		else
			echo -e "${BOLD}   ::${NORMAL} Skipping ${x}..."
		fi
	done
}

uppercase(){
	# needs tr on busybox
	echo $1 | tr 'a-z' 'A-Z'
}


findmediamount() {
	# $1 = mount dir name / media name
	# $2 = recognition file
	# $3 = variable to have the device path
	# $4 = directory before /mnt, like NEW_ROOT
	# args remaining are possible devices 

	local media=$1 recon=$2 vrbl=$3
	local mntdir="${4}/mnt/${media}"
	shift 4

	good_msg "Looking for the ${media}" ${CRYPT_SILENT}

	if [ "$#" -gt "0" ]
	then
		[ ! -d "${mntdir}" ] && mkdir -p ${mntdir} 2>/dev/null >/dev/null
		if [ -n "${ISOBOOT}" ]
		then
			mntcddir="${mntdir%${media}}iso"
			if [ ! -f ${mntcddir} ]
			then
				mkdir ${mntcddir}
			fi
		else
			mntcddir=${mntdir}
		fi

		for x in $*
		do
			# Check for a block device to mount
			if [ -b "${x}" ]
			then
				skip=0
				bsn=`basename "${x}"`
				#
				# If disk and it has at least one partition, skip.
				# We use /sys/block/${bsn}/${bsn}[0-9]* to make sure that we
				# don't skip device mapper devices. Even the craziest scenario
				# deserves a fair chance.
				#
				for part in `ls /sys/block/${bsn}/${bsn}[0-9]* 2>/dev/null`
				do
					skip=1
					break;
				done
				if [ ${skip} -eq 1 ]
				then
					continue
				fi
				good_msg "Attempting to mount media:- ${x}" ${CRYPT_SILENT}

#				if [ "${media}" = "cdrom" ]; then
#					mount -r -t iso9660 ${x} ${mntdir} &>/dev/null
#				else
#					mount -r -t auto ${x} ${mntdir} &>/dev/null
#				fi
				mount -t ${CDROOT_TYPE} ${x} ${mntcddir} >/dev/null 2>&1
				if [ "$?" = '0' ]
				then
					if [ -n "${ISOBOOT}" ]; then
						if [ -f ${mntcddir}/${ISOBOOT} ]; then
							mount -o loop ${mntcddir}/${ISOBOOT} ${mntdir}
							if [ "$?" = "0" ]; then
								good_msg "iso mounted on ${mntdir}"
							fi
						fi
					fi

					# Check for the media
					if [ -f "${mntdir}/${recon}" ]
					then
						#set REAL_ROOT, CRYPT_ROOT_KEYDEV or whatever ${vrbl} is
						eval ${vrbl}'='"${x}"
						good_msg "Media found on ${x}" ${CRYPT_SILENT}
						break
					else
						umount ${mntcddir}
					fi
				fi
			fi
		done
	fi

	eval local result='$'${vrbl}

	[ -n "${result}" ] || bad_msg "Media not found" ${CRYPT_SILENT}
}

devicelist(){
	# Locate the cdrom device with our media on it.
	# USB Keychain/Storage
	local DEVICES="/dev/sd*"
	# CDROM DEVICES
	DEVICES="$DEVICES /dev/cdroms/* /dev/ide/cd/* /dev/sr*"
	# IDE devices
	DEVICES="$DEVICES /dev/hd*"
	# USB using the USB Block Driver
	DEVICES="$DEVICES /dev/ubd* /dev/ubd/*"
	# iSeries devices
	DEVICES="$DEVICES /dev/iseries/vcd*"
	echo ${DEVICES}
}

bootstrapCD() {
	local DEVICES=`devicelist`
	# The device was specified on the command line, so there's no need to scan
	# a bunch of extra devices
	[ -n "${CDROOT_DEV}" ] && DEVICES="${CDROOT_DEV}"

	findmediamount "cdrom" "${SUBDIR}/livecd" "REAL_ROOT" "${NEW_ROOT}" ${DEVICES}
}

bootstrapKey() {
	# $1 = ROOT/SWAP
	local KEYDEVS=`devicelist`
	eval local keyloc='"${CRYPT_'${1}'_KEY}"'

	findmediamount "key" "${keyloc}" "CRYPT_${1}_KEYDEV" "" ${KEYDEVS}
}

cache_cd_contents() {
	# Check loop file exists and cache to ramdisk if DO_cache is enabled
	if [ "${LOOPTYPE}" != "noloop" ] && [ "${LOOPTYPE}" != "sgimips" ]
	then
		check_loop
		if [ "${DO_cache}" ]
		then
			# TODO: Check the size of the image versus the size of our tmpfs
			# along with the amount of available RAM and increase tmpfs size
			# if necessary. (Not having awk sucks...)
			# z=0
			# for i in $(cat /proc/meminfo | grep -e ^MemFree -e ^Cached | \
			# cut -d: -f2 | cut -dk -f1 | sed -e "s/^\s*//") ; do
			# z=$(($z + $i)) ; done
			# echo $z
			good_msg "Copying loop file for caching..."
			# Verify that the needed directory exists
			mkdir -p "$(dirname ${NEW_ROOT}/mnt/${LOOP})"
			cp -a ${NEW_ROOT}/mnt/cdrom/${LOOP} ${NEW_ROOT}/mnt/${LOOP}
			if [ $? -ne 0 ]
			then
				bad_msg "Failed to cache the loop file! Lack of space?"
				rm -rf ${NEW_ROOT}/mnt/livecd.* 2>/dev/null
				rm -rf ${NEW_ROOT}/mnt/image.* 2>/dev/null
				rm -rf ${NEW_ROOT}/mnt/zisofs 2>/dev/null
			else
				LOOPEXT='../'
			fi
		fi
	fi
}

mount_sysfs() {
	mount -t sysfs sysfs /sys -o noexec,nosuid,nodev >/dev/null 2>&1
	ret=$?
	[ ${ret} -eq 0 ] || bad_msg "Failed to mount /sys!"
}

# Insert a directory tree $2 to an union specified by $1
# Top-level read-write branch is specified by it's index 0
# $1 = union absolute path (starting with /)
# $2 = path to data directory
#
union_insert_dir() {
	# Always mount it over the precedent (add:1:)
	mount -n -o remount,add:1:$2=rr aufs $1
	if [ $? = '0' ]
	then
		good_msg "Addition of $2 to $1 successful"
	fi
}

# Insert all modules found in $1, usually mnt/cdrom
# added to allow users to add their own apps.
union_insert_modules() {
	for module in `ls ${NEW_ROOT}/$1/modules/*.mo 2>/dev/null| sort`
	do
		mkdir -p ${MEMORY}/modules/`basename ${module} .mo`
		mount -o loop,ro ${module} ${MEMORY}/modules/`basename ${module} .mo`
		union_insert_dir $UNION ${MEMORY}/modules/`basename ${module} .mo`
	done
	for module in `ls ${NEW_ROOT}/$1/modules/*.lzm 2>/dev/null| sort`
	do
		mkdir -p ${MEMORY}/modules/`basename ${module} .lzm`
		mount -o loop,ro ${module} ${MEMORY}/modules/`basename ${module} .lzm`
		union_insert_dir $UNION ${MEMORY}/modules/`basename ${module} .lzm`
	done
}

# Function to create an ext2 fs on $CHANGESDEV, $CHANGESMNT mountpoint
create_changefs() {
	local size
	while [ 1 ]
	do
		read -p '<< Size of file (Enter for default 256 Mb): ' size
		if [ -z "$size" ]; then
			let size=256
		fi
		let size="$size"
		if [ $size -lt 16 ]
		then
			bad_msg "Please give a size of at least 16 Mb"
		else
			dd if=/dev/zero of=$CHANGESMNT/livecd.aufs bs=1M count=$size
			if [ $? = '0' ]
			then
				good_msg "Creation of livecd.aufs, $size Mb on $CHANGESDEV successful, formatting it ext2"
				mke2fs -F $CHANGESMNT/livecd.aufs
				break
			else
				rm -f $CHANGESMNT/livecd.aufs
				bad_msg "Unable to create livecd.aufs on $CHANGESDEV of $size Mb"
				bad_msg "Please give a size of at least 16 Mb"
				bad_msg "Also check if your disk is full or read-only ?"
				read -p '<< Type "a" to abort, anything else to continue : ' doabort
				if [ "$doabort" = "a" ]; then
					return 1
				fi
			fi
		fi
	done
	return 0
}

setup_aufs() {
	if [ "${USE_AUFS_NORMAL}" -eq '1' ]
 	then
		# Directory used for rw changes in union mount filesystem
		UNION=/union
		MEMORY=/memory
		# Mountpoint for the changesdev
		CHANGESMNT=$NEW_ROOT/mnt/changesdev
		if [ -z "$UID" ]
		then
			CHANGES=$MEMORY/aufs_changes/default
		else
			CHANGES=$MEMORY/aufs_changes/$UID
		fi

		mkdir -p ${MEMORY}
		mkdir -p ${UNION}
		mkdir -p ${CHANGESMNT}
		for i in dev mnt mnt/cdrom mnt/livecd mnt/key tmp tmp/.initrd mnt/gentoo sys
		do
			mkdir -p "${NEW_ROOT}/${i}"
			chmod 755 "${NEW_ROOT}/${i}"
		done
		[ ! -e "${NEW_ROOT}/dev/null" ] && mknod "${NEW_ROOT}"/dev/null c 1 3
		[ ! -e "${NEW_ROOT}/dev/console" ] && mknod "${NEW_ROOT}"/dev/console c 5 1

		bootstrapCD
		if [ -n "${AUFS}" ]
		then
			if [ "${AUFS}" = "detect" ]
			then
				CHANGESMNT="${NEW_ROOT}/mnt/cdrom"
				CHANGESDEV=${REAL_ROOT}
			else
				CHANGESDEV=${AUFS}
				good_msg "mounting $CHANGESDEV to $MEMORY for aufs support"
	#			mount -t auto $CHANGESDEV $MEMORY
				mount -t auto $CHANGESDEV $CHANGESMNT
				ret=$?
				if [ "${ret}" -ne 0 ]
				then
					bad_msg "mount of $CHANGESDEV failed falling back to ramdisk based aufs"
					unset AUFS
				fi
			fi
			# Check and attempt to create the changesfile
			if [ ! -e $CHANGESMNT/livecd.aufs ] && [ -n "${AUFS}" ]
			then
				create_changefs
				mount -t auto $CHANGESMNT/livecd.aufs $MEMORY
			elif [ -n "${AUFS}" ]
			then
				local nbpass=0
				while [ 1 ]
				do
					mount -t auto $CHANGESMNT/livecd.aufs $MEMORY
					ret=$?
					if [ "${ret}" -ne 0 ]
					then
						if [ $nbpass -eq 0 ]
						then
							bad_msg "mounting of changes file failed, Running e2fsck"
							e2fsck $CHANGESMNT/livecd.aufs
							nbpass=$(($nbpass + 1))
						else
							bad_msg "mount of $CHANGESDEV failed falling back to ramdisk based aufs"
							bad_msg "your livecd.aufs might be messed up, and I couldn't fix it"
							bad_msg "moving livecd.aufs to livecd.aufs.bad"
							mv $CHANGESMNT/livecd.aufs $CHANGESMNT/livecd.aufs.bad
							bad_msg "try to fix it yourself with e2fsck later on, sorry for disturbing"
							break
						fi
					else
						if [ $nbpass -eq 1 ]
						then
							good_msg "e2fsck seemed successful. Please check your files after bootup"
						fi
						break
					fi
				done
				if [ -f ${MEMORY}/.doclean.sh ]
				then
					good_msg "finishing the permanent changes cleanup"
					. ${MEMORY}/.doclean.sh
					rm ${MEMORY}/.doclean.sh
				fi
			fi
			# mount tmpfs only in the case when changes= boot parameter was
			# empty or we were not able to mount the storage device
			if [ "${CDROOT}" -eq '1' -a ! -f ${CHANGESMNT}/livecd.aufs  ]
			then
				umount $MEMORY
				bad_msg "failed to find livecd.aufs file on $CHANGESDEV"
				bad_msg "create an ext2 livecd.aufs file on this device if you wish to use it for aufs"
				bad_msg "falling back to ramdisk based aufs for safety"
				mount -t tmpfs tmpfs $MEMORY
				XINO=$MEMORY
			else
				XINO=$MEMORY/xino
				mkdir -p $XINO
				mount -t tmpfs tmpfs $XINO
			fi
		else 
			good_msg "Mounting ramdisk to $MEMORY for aufs support..."
			mount -t tmpfs tmpfs $MEMORY
			XINO=$MEMORY
		fi 

		mkdir -p $CHANGES
		mount -t aufs -n -o nowarn_perm,udba=none,xino=$XINO/.aufs.xino,br:$CHANGES=rw aufs ${UNION}
		ret=$?
		if [ "${ret}" -ne 0 ]
		then 
			bad_msg "Can't setup union ${UNION} in directory!"
			USE_AUFS_NORMAL=0
		fi
	else
		USE_AUFS_NORMAL=0
	fi
}

findnfsmount() {
	if [ "${IP}" != '' ] || busybox udhcpc -n -T 15 -q
	then
		[ -e /rootpath ] && NFSROOT=`cat /rootpath`

		if [ "${NFSROOT}" = '' ]
		then
			# Obtain NFSIP	
			OPTIONS=`busybox dmesg | grep rootserver | sed -e "s/,/ /g"`
			for OPTION in $OPTIONS
			do
				if [ `echo $OPTION | sed -e "s/=/ /g" | cut -d " " -f 1` = 'rootserver' ]
				then
					NFSIP=`echo $OPTION | sed -e "s/=/ /g" | cut -d " " -f 2`
				fi 
			done
			
			# Obtain NFSPATH
			OPTIONS=`busybox dmesg | grep rootpath | sed -e "s/,/ /g"`	
			for OPTION in $OPTIONS
			do
				if [ `echo $OPTION | sed -e "s/=/ /g" | cut -d " " -f 1` = 'rootpath' ]
				then
					NFSPATH=`echo $OPTION | sed -e "s/=/ /g" | cut -d " " -f 2`
		 		fi
			done

			# Setup NFSROOT
			if [ "${NFSIP}" != '' ] && [ "$NFSPATH" != '' ]
			then
				NFSROOT="${NFSIP}:${NFSPATH}"
			else
				bad_msg "The DHCP Server did not send a valid root-path."
				bad_msg "Please check your DHCP setup, or provide a nfsroot=<...> parameter."
			fi
		fi

		if [ "${NFSROOT}" != '' ]
		then
			NFSOPTIONS=${NFSROOT#*,}
			NFSROOT=${NFSROOT%%,*}
			if [ "${NFSOPTIONS}" = "${NFSROOT}" ]
			then
				NFSOPTIONS=$DEFAULT_NFSOPTIONS
			else
				NFSOPTIONS="${DEFAULT_NFSOPTIONS},${NFSOPTIONS}"
			fi

			if [ "${CDROOT}" != '0' ]
			then
				good_msg "Attempting to mount NFS CD image on ${NFSROOT} with options ${NFSOPTIONS}"
				mount -t nfs -o ${NFSOPTIONS} ${NFSROOT} ${NEW_ROOT}/mnt/cdrom
				if [ "$?" = '0' ]
				then
					REAL_ROOT="/dev/nfs"
				else
					bad_msg "NFS Mounting failed. Is the path corrent ?"
				fi
			else	
				good_msg "Attempting to mount NFS root on ${NFSROOT} with options ${NFSOPTIONS}"
				mount -t nfs -o ${NFSOPTIONS} ${NFSROOT} ${NEW_ROOT}
				if [ "$?" = '0' ]
				then
					REAL_ROOT="/dev/nfs"
				else
					bad_msg "NFS Mounting failed. Is the path correct ?"
				fi
				# FIXME: Need to start portmap and the other rpc daemons in
				# order to remount rw.
			fi

		fi
	fi
}

check_loop() {
	if [ "${LOOP}" = '' -o ! -e "mnt/cdrom/${LOOP}" ]
	then
	
		bad_msg "Invalid loop location: ${LOOP}"
		bad_msg 'Please export LOOP with a valid location, or reboot and pass a proper loop=...'
		bad_msg 'kernel command line!'
	
		run_shell
	fi
}

run_shell() {
	/bin/ash
}

runmdev() {
	# Use devtmpfs if enabled in kernel,
	# else tmpfs. Always run mdev just in case
	devfs=tmpfs
	if grep -qs devtmpfs /proc/filesystems ; then
		devfs=devtmpfs
	fi

	# Options copied from /etc/init.d/udev-mount, should probably be kept in sync
	mount -t $devfs -o "exec,nosuid,mode=0755,size=10M" udev /dev \
		|| bad_msg "Failed to mount /dev as ${devfs}"

	# http://git.busybox.net/busybox/plain/docs/mdev.txt
	mkdir -m 0755 /dev/pts
	mount -t devpts -o gid=5,mode=0620 devpts /dev/pts  || bad_msg "Failed to mount /dev/pts"
	mdev -s  || bad_msg "Failed to receive dynamic updates from mdev"
}

test_success() {
	retcode=$?
	# If last command failed send error message and fall back to a shell	
	if [ "$retcode" != '0' ]
	then
		error_string=$1
		error_string="${error_string:-run command}"
		bad_msg 'Failed to $1; failing back to the shell...'
		run_shell
	fi
}


# msg functions arguments
# $1 string
# $2 hide flag

good_msg() {	
	msg_string=$1
	msg_string="${msg_string:-...}"
	[ "$2" != 1 ] && echo -e "${GOOD}>>${NORMAL}${BOLD} ${msg_string} ${NORMAL}"
}

bad_msg() {
	msg_string=$1
	msg_string="${msg_string:-...}"
	if [ "$2" != 1 ]
	then
		splash 'verbose' > /dev/null &
		echo -e "${BAD}!!${NORMAL}${BOLD} ${msg_string} ${NORMAL}"
	fi
} 

warn_msg() {
	msg_string=$1
	msg_string="${msg_string:-...}"
	[ "$2" != 1 ] && echo -e "${WARN}**${NORMAL}${BOLD} ${msg_string} ${NORMAL}"
}

crypt_filter() {
	if [ "${CRYPT_SILENT}" = '1' ]
	then
		eval $1 >/dev/null 2>/dev/null
	else
		splash 'verbose' > /dev/null &
		eval $1
		if [ $? -eq 0 ]
		then
			splash set_msg 'Disk unlocked.'
		fi
	fi
}

prompt_user(){
	# $1 = variable whose value is the path (examples: "REAL_ROOT",
	#      "LUKS_KEYDEV")
	# $2 = label
	# $3 = optional explanations for failure

	eval local oldvalue='$'${1}

	[ \( $# != 2 \) -a \( $# != 3 \) ] && \
		bad_msg "Bad invocation of function prompt_user, please file a bug \
		report with this message" && exit 1
	[ -n "${3}" ] && local explnt=" or : ${3}" || local explnt="."
	
	bad_msg "Could not find the ${2} in ${oldvalue}${explnt}"
	echo '   Please specify another value or: press Enter for the same, type "shell" for a shell, or "q" to skip...'
	echo -n "${2}(${oldvalue}) :: "
	read ${1}
	case `eval echo '$'${1}` in
		'q')
			eval ${1}'='${oldvalue}
			warn_msg "Skipping step, this will likely cause a boot failure."
			break
			;;
		'shell')
			eval ${1}'='${oldvalue}
			echo "To leave and try again just press <Ctrl>+D"
			run_shell
			;;
		'')
			eval ${1}'='${oldvalue}
			;;
	esac
}

setup_hotplug() {
	if [ "${KV_2_6_OR_GREATER}" ]
	then
		echo /sbin/mdev > /proc/sys/kernel/hotplug
	fi
}

setup_slowusb() {
	# This function removes unset DO_slowusb if there is no usb-storage attached.
	# If noslowusb is set, skip this function
	[ "${DO_slowusb}" ] || return

	# Unset DO_slowusb, so we can set it again if usb-storage has something attached
	unset DO_slowusb

	local usb_storage_dir="/sys/bus/usb/drivers/usb-storage"
	if [ ! -d "${usb_storage_dir}" ]
	then
		# no automated slowusb required. no usb-storage devices attached.
		return
	fi
	for x in "${usb_storage_dir}"/*
	do
		[ -d "${x}" ]  && [ "${x}" != "${usb_storage_dir}/module" ] \
			&& { DO_slowusb="1" ; break ; }
	done
}

start_dev_mgr() {
	if [ "${KV_2_6_OR_GREATER}" ]
	then
		cd /sys
		good_msg 'Activating mdev'
		runmdev
		cd /
	fi
}

cmdline_hwopts() {
	# Scan CMDLINE for any "doscsi" or "noscsi"-type arguments
	local FOUND
	local TMP_HWOPTS

	for x in $HWOPTS
	do
		for y in $CMDLINE
		do
			if [ "${y}" = "do${x}" ]
			then
				MY_HWOPTS="${MY_HWOPTS} $x"
			elif [ "${y}" = "no${x}" ]
			then
				MY_HWOPTS="`echo ${MY_HWOPTS} | sed -e \"s/${x}//g\" -`"
			fi
			if [ "$(echo ${y} | cut -b -7)" = "keymap=" ]
			then
				MY_HWOPTS="${MY_HWOPTS} keymap"
			fi
		done
	done
   
	# Shouldnt need to sort this as the following loop should figure out the
	# duplicates and strip them out
	#MY_HWOPTS=`echo ${MY_HWOPTS}|  sort`
	
	for x in ${MY_HWOPTS}
	do
		FOUND=0
		for y in ${TMP_HWOPTS}
		do
			if [ "${y}" = "${x}" ]
			then 
				continue 2
			fi
		done
		TMP_HWOPTS="${TMP_HWOPTS} ${x}"
		eval DO_`echo ${x} | sed 's/-//'`=1
	done

	MY_HWOPTS=${TMP_HWOPTS}
}

load_modules() {
	# Load modules listed in MY_HWOPTS if /lib/modules exists for the running
	# kernel version
	if [ -d "/lib/modules/${KV}" ]
	then
		good_msg 'Loading modules'
		# Load appropriate kernel modules
		for modules in $MY_HWOPTS
		do
			modules_scan $modules
		done
	else
		good_msg 'Skipping module load; no modules in the ramdisk!'
	fi
}

setup_keymap() {
	if [ -e $MEMORY/keyboard ]
	then
		. $MEMORY/keyboard
		loadkmap < /lib/keymaps/${XKEYBOARD}.map
	elif [ "${DO_keymap}" ]
	then
		if [ ! -e /dev/vc/0 -a ! -e /dev/tty0 ]
		then
			DEVBIND=1
			mount -o bind ${NEW_ROOT}/dev /dev
		fi
		[ ! -e /dev/tty0 ] && ln -s /dev/tty1 /dev/tty0

		[ -f /lib/keymaps/keymapList ] && chooseKeymap

		[ "${DEVBIND}" = '1' ] && umount /dev
		
		if [ -e /etc/sysconfig/keyboard -a "${USE_AUFS_NORMAL}" = '1' ]
		then
			cp /etc/sysconfig/keyboard $MEMORY
		elif [ -e /etc/sysconfig/keyboard -a "${CDROOT}" = '1' ]
		then
			mkdir -p ${NEW_ROOT}/etc/sysconfig/
			cp /etc/sysconfig/keyboard ${NEW_ROOT}/etc/sysconfig/keyboard
		fi
	fi
}

chooseKeymap() {
	good_msg "Loading keymaps"
	if [ -z "${keymap}" ]
	then
		splash 'verbose' > /dev/null &
		cat /lib/keymaps/keymapList
		read -t 10 -p '<< Load keymap (Enter for default): ' keymap
		case ${keymap} in
			1|azerty) keymap=azerty ;;
			2|be) keymap=be ;;
			3|bg) keymap=bg ;;
			4|br-a) keymap=br-a ;;
			5|br-l) keymap=br-l ;;
			6|by) keymap=by ;;
			7|cf) keymap=cf ;;
			8|croat) keymap=croat ;;
			9|cz) keymap=cz ;;
			10|de) keymap=de ;;
			11|dk) keymap=dk ;;
			12|dvorak) keymap=dvorak ;;
			13|es) keymap=es ;;
			14|et) keymap=et ;;
			15|fi) keymap=fi ;;
			16|fr) keymap=fr ;;
			17|gr) keymap=gr ;;
			18|hu) keymap=hu ;;
			19|il) keymap=il ;;
			20|is) keymap=is ;;
			21|it) keymap=it ;;
			22|jp) keymap=jp ;;
			23|la) keymap=la ;;
			24|lt) keymap=lt ;;
			25|mk) keymap=mk ;;
			26|nl) keymap=nl ;;
			27|no) keymap=no ;;
			28|pl) keymap=pl ;;
			29|pt) keymap=pt ;;
			30|ro) keymap=ro ;;
			31|ru) keymap=ru ;;
			32|se) keymap=se ;;
			33|sg) keymap=sg ;;
			34|sk-y) keymap=sk-y ;;
			35|sk-z) keymap=sk-z ;;
			36|slovene) keymap=slovene ;;
			37|trf) keymap=trf ;;
			38|trq) keymap=trq ;;
			39|ua) keymap=ua ;;
			40|uk) keymap=uk ;;
			41|us) keymap=us ;;
			42|wangbe) keymap=wangbe ;;
			43|ch*) keymap=ch\(fr\) ;;
		esac
	fi
	if [ -e /lib/keymaps/${keymap}.map ]
	then
		good_msg "Loading the ''${keymap}'' keymap"
		loadkmap < /lib/keymaps/${keymap}.map
#		xkeymap=${keymap}
#		echo ${keymap} | egrep -e "[0-9]+" >/dev/null 2>&1
#		if [ $? -eq 0 ]
#		then
#			xkeymap=`tail -n 7 /lib/keymaps/keymapList | grep ${keymap} | sed -r "s/.*\s+${keymap}\s+([a-z-]+).*/\1/g" | egrep -v 1`
#		fi
		mkdir -p /etc/sysconfig
#		echo "XKEYBOARD=${xkeymap}" > /etc/sysconfig/keyboard
		echo "XKEYBOARD=\"${keymap}\"" > /etc/sysconfig/keyboard
		splash set_msg "Set keymap to ${keymap}"
	elif [ -z "${keymap}" ]
	then
		echo
		good_msg "Keeping default keymap"
		splash set_msg "Keeping default keymap"
		mkdir -p /etc/sysconfig
		echo "XKEYBOARD=us" > /etc/sysconfig/keyboard
	else
		bad_msg "Sorry, but keymap ''${keymap}'' is invalid!"
		unset keymap
		chooseKeymap
	fi
}

startVolumes() {
	#good_msg 'Checking if volumes need to be started...'

	# Here, we check for /dev/device-mapper, and if it exists, we setup a
	# a symlink, which should hopefully fix bug #142775 and bug #147015
	if [ -e /dev/device-mapper ] && [ ! -e /dev/mapper/control ]
	then
		mkdir -p /dev/mapper
		ln -sf /dev/device-mapper /dev/mapper/control
	fi
	
	if [ "${USE_MDADM}" = '1' ]
	then
		/sbin/mdadm --assemble --scan
	fi

	if [ "${USE_DMRAID_NORMAL}" = '1' ]
	then
		if [ -e '/sbin/dmraid' ]
		then
			good_msg "Activating Device-Mapper RAID(s)"
			if [ '${DMRAID_OPTS}' = '' ]
			then
				/sbin/dmraid -ay
			else
				/sbin/dmraid -ay ${DMRAID_OPTS}
			fi
		fi
	fi

	if [ "${USE_LVM_NORMAL}" = '1' ]
	then
		if [ -e '/bin/lvm' ]
		then
			for dev in ${RAID_DEVICES}
			do
				setup_md_device "${dev}"
			done

			# This is needed for /bin/lvm to accept the following logic
			lvm_commands="#! /bin/lvm"

			# If there is a cahe, update it. Unbreak at least dmcrypt
			[ -d /etc/lvm/cache ] && lvm_commands="${lvm_commands} \nvgscan"

			# To activate volumegroups on all devices in the cache
			lvm_commands="${lvm_commands} \nvgchange -ay --sysinit"

			# And finally execute it all (/proc/... needed if lvm is compiled without readline)
			good_msg "Scanning for and activating Volume Groups"
			printf "%b\n" "${lvm_commands}" | /bin/lvm /proc/self/fd/0
		else
			bad_msg "vgscan or vgchange not found: skipping LVM volume group activation!"
		fi
	fi
}

startiscsi() {
	
	if [ ! -n "${ISCSI_NOIBFT}" ]
	then
		good_msg "Activating iSCSI via iBFT"
		iscsistart -b
	fi

	if [ -n "${ISCSI_INITIATORNAME}" ] && [ -n "${ISCSI_TARGET}" ] && [ -n "${ISCSI_ADDRESS}" ]
	then
		good_msg "Activating iSCSI via cmdline"

		if [ "${ISCSI_TGPT}" ]
		then
			ADDITIONAL="${ADDITIONAL} -g ${ISCSI_TGPT}"
		else
			ADDITIONAL="${ADDITIONAL} -g 1"
		fi
		
		if [ "${ISCSI_PORT}" ]
		then
			ADDITIONAL="${ADDITIONAL} -p ${ISCSI_PORT}"
		fi

		if [ "${ISCSI_USERNAME}" ]
		then
			ADDITIONAL="${ADDITIONAL} -u ${ISCSI_USERNAME}"
		fi

		if [ "${ISCSI_PASSWORD}" ]
		then
			ADDITIONAL="${ADDITIONAL} -w ${ISCSI_PASSWORD}"
		fi

		if [ "${ISCSI_USERNAME_IN}" ]
		then
			ADDITIONAL="${ADDITIONAL} -U ${ISCSI_USERNAME_IN}"
		fi

		if [ "${ISCSI_PASSWORD_IN}" ]
		then
			ADDITIONAL="${ADDITIONAL} -W ${ISCSI_PASSWORD_IN}"
		fi

		if [ "${ISCSI_DEBUG}" ]
		then
			ADDITIONAL="${ADDITIONAL} -d ${ISCSI_DEBUG}"
		fi

		iscsistart -i "${ISCSI_INITIATORNAME}" -t "${ISCSI_TARGET}" -a "${ISCSI_ADDRESS}" ${ADDITIONAL}

		# let iscsid settle - otherwise mounting the iSCSI-disk will fail (very rarely, though)
		sleep 1
	fi
}


# Open a LUKS device
# It is either the root or a swap, other devices are supported in the scripts provided with sys-fs/cryptsetup-luks
# $1 - root/swap
openLUKS() {
	# please use 'tr' and this line, or remove it
	# eval local TYPE=`uppercase $1`

	case $1 in
		root)
			local TYPE=ROOT
			;;
		swap)
			local TYPE=SWAP
			;;
	esac

	eval local LUKS_DEVICE='"${CRYPT_'${TYPE}'}"' LUKS_NAME="$1" LUKS_KEY='"${CRYPT_'${TYPE}'_KEY}"' LUKS_KEYDEV='"${CRYPT_'${TYPE}'_KEYDEV}"'
	local DEV_ERROR=0 KEY_ERROR=0 KEYDEV_ERROR=0
	local mntkey="/mnt/key/" cryptsetup_options=''

	[ ! -e /sbin/cryptsetup ] && bad_msg "The ramdisk does not support LUKS" && exit 1
	while [ 1 ]
	do
		local gpg_cmd=""
		# if crypt_silent=1 and some error occurs, enter shell quietly
		if [ \( ${CRYPT_SILENT} -eq 1 \) -a \( \( \( ${DEV_ERROR} -eq 1 \) -o \( ${KEY_ERROR} -eq 1 \) \) -o \( ${KEYDEV_ERROR} -eq 1 \) \) ]
		then
			run_shell
		elif [ ${DEV_ERROR} -eq 1 ]
		then
			prompt_user "LUKS_DEVICE" "${LUKS_NAME}"
			DEV_ERROR=0
		elif [ ${KEY_ERROR} -eq 1 ]
		then
			prompt_user "LUKS_KEY" "${LUKS_NAME} key"
			KEY_ERROR=0
		elif [ ${KEYDEV_ERROR} -eq 1 ]
		then
			prompt_user "LUKS_KEYDEV" "${LUKS_NAME} key device"
			KEYDEV_ERROR=0
		else
			case "${LUKS_DEVICE}" in
				UUID\=*|LABEL\=*)
					local REAL_LUKS=""
					local retval=1

					if [ "${retval}" -ne 0 ]; then
						REAL_LUKS=`findfs "${LUKS_DEVICE}" 2>/dev/null`
						retval=$?
					fi

					if [ "$retval" -ne 0 ]; then
						REAL_LUKS=`busybox findfs "${LUKS_DEVICE}" 2>/dev/null`
						retval=$?
					fi

					if [ "${retval}" -ne 0 ]; then
						REAL_LUKS=`blkid -l -t "${LUKS_DEVICE}" | cut -d ":" -f 1 2>/dev/null`
						retval=$?
					fi

					if [ "${retval}" -eq 0 ] && [ -n "${REAL_LUKS}" ]; then
						good_msg "Detected device ${REAL_LUKS}"
						LUKS_DEVICE="${REAL_LUKS}"
					fi
				;;
			esac

			setup_md_device ${LUKS_DEVICE}
			cryptsetup isLuks ${LUKS_DEVICE}
			if [ $? -ne 0 ]
			then
				bad_msg "The LUKS device ${LUKS_DEVICE} does not contain a LUKS header" ${CRYPT_SILENT}
				DEV_ERROR=1
				continue
			else
				# Handle keys
				if [ -n "${LUKS_KEY}" ] 
				then
					if [ ! -e "${mntkey}${LUKS_KEY}" ] 
					then
						if [ -b "${LUKS_KEYDEV}" ]
						then good_msg "Using key device ${LUKS_KEYDEV}." ${CRYPT_SILENT}
						else
							good_msg "Please insert removable device ${LUKS_KEYDEV} for ${LUKS_NAME}" ${CRYPT_SILENT}
							# abort after 10 secs
							local count=10
							while [ ${count} -gt 0 ]
							do 
								count=$((count-1))
								sleep 1
								if [ -b "${LUKS_KEYDEV}" ]
								then
									good_msg "Removable device ${LUKS_KEYDEV} detected." ${CRYPT_SILENT}
									break
								fi
							done
							if [ ! -b "${LUKS_KEYDEV}" ]
							then
								eval CRYPT_${TYPE}_KEY=${LUKS_KEY}
								bootstrapKey ${TYPE}
								eval LUKS_KEYDEV='"${CRYPT_'${TYPE}'_KEYDEV}"'
								if [ ! -b "${LUKS_KEYDEV}" ]; then
									KEYDEV_ERROR=1
									bad_msg "Removable device ${LUKS_KEYDEV} not found." ${CRYPT_SILENT}
									continue
								fi
								# continue otherwise will mount keydev which is mounted by bootstrap
								continue
							fi
						fi
						# At this point a device was recognized, now let's see if the key is there
						[ ! -d "$mntkey" ] && mkdir -p ${mntkey} 2>/dev/null >/dev/null

						mount -n -o ro ${LUKS_KEYDEV} ${mntkey} >/dev/null 2>/dev/null
						if [ "$?" != '0' ]
						then
							KEYDEV_ERROR=1
							bad_msg "Mounting of device ${LUKS_KEYDEV} failed." ${CRYPT_SILENT}
							continue
						else
							good_msg "Removable device ${LUKS_KEYDEV} mounted." ${CRYPT_SILENT}
							sleep 2
							# keyfile exists?
							if [ ! -e "${mntkey}${LUKS_KEY}" ]; then
								umount -n ${mntkey} 2>/dev/null >/dev/null
								KEY_ERROR=1
								KEYDEV_ERROR=1
								bad_msg "Key {LUKS_KEY} on device ${LUKS_KEYDEV} not found." ${CRYPT_SILENT}
								continue
							fi
						fi
					fi
					# At this point a candidate key exists (either mounted before or not)
					good_msg "${LUKS_KEY} on device ${LUKS_KEYDEV} found" ${CRYPT_SILENT}
					if [ $(echo ${LUKS_KEY} | grep -o '.gpg$') = ".gpg" ] && [ -e /sbin/gpg ] ; then
						[ -e /dev/tty ] && mv /dev/tty /dev/tty.org
						mknod /dev/tty c 5 1
						cryptsetup_options="-d -"
						gpg_cmd="/sbin/gpg --logger-file /dev/null --quiet --decrypt ${mntkey}${LUKS_KEY} |"
					else
						cryptsetup_options="-d ${mntkey}${LUKS_KEY}"
					fi
				fi
				# At this point, keyfile or not, we're ready!
				crypt_filter "${gpg_cmd}cryptsetup ${cryptsetup_options} luksOpen ${LUKS_DEVICE} ${LUKS_NAME}"
				if [ $? -eq 0 ]
				then
					good_msg "LUKS device ${LUKS_DEVICE} opened" ${CRYPT_SILENT}
					break
				else
					bad_msg "Failed to open LUKS device ${LUKS_DEVICE}" ${CRYPT_SILENT}
					DEV_ERROR=1
					KEY_ERROR=1
					KEYDEV_ERROR=1
				fi
			fi
		fi
	done
	umount ${mntkey} 2>/dev/null >/dev/null
	rmdir -p ${mntkey} 2>/dev/null >/dev/null
}

startLUKS() {

	# if key is set but key device isn't, find it
	
	[ -n "${CRYPT_ROOT_KEY}" ] && [ -z "${CRYPT_ROOT_KEYDEV}" ] \
		&& sleep 6 && bootstrapKey "ROOT"

	if [ -n "${CRYPT_ROOT}" ]; then
		openLUKS "root"
		if [ -n "${REAL_ROOT}" ]
		then
			# Rescan volumes
			startVolumes
		else
			REAL_ROOT="/dev/mapper/root"
		fi
	fi

	# same for swap, but no need to sleep if root was unencrypted
	[ -n "${CRYPT_SWAP_KEY}" ] && [ -z "${CRYPT_SWAP_KEYDEV}" ] \
		&& { [ -z "${CRYPT_ROOT}" ] && sleep 6; bootstrapKey "SWAP"; }

	if [ -n "${CRYPT_SWAP}" ]; then
		openLUKS "swap"
		if [ -z "${REAL_RESUME}" ]
		then
			# Resume from swap as default
			REAL_RESUME="/dev/mapper/swap"
		fi
	fi
}

sdelay() {
	# Sleep a specific number of seconds if SDELAY is set
	if [ "${SDELAY}" ]
	then
		good_msg "Waiting ${SDELAY} seconds..."
		sleep ${SDELAY}
	else
		good_msg 'Hint: Use parameter scandelay[=seconds] if you need waiting here'
	fi
}

quiet_kmsg() {
	# if QUIET is set make the kernel less chatty
	[ -n "$QUIET" ] && echo '0' > /proc/sys/kernel/printk
}

verbose_kmsg() {
	# if QUIET is set make the kernel less chatty
	[ -n "$QUIET" ] && echo '6' > /proc/sys/kernel/printk
}


cdupdate() {
	if [ "${CDROOT}" = '1' ]
	then
		if [ -x /${NEW_ROOT}/mnt/cdrom/cdupdate.sh ]
		then
			good_msg "Running cdupdate.sh"
			${NEW_ROOT}/mnt/cdrom/cdupdate.sh
			if [ "$?" != '0' ]
			then
				bad_msg "Executing cdupdate.sh failed!"
				run_shell
			fi
		else
			good_msg 'No cdupdate.sh script found, skipping...'
		fi
	fi
}

setup_btrfsctl() {
	# start BTRFS volume detection, if available
	[ -x /sbin/btrfsctl ] && /sbin/btrfsctl -a
}

setup_md_device() {
	local device

	[ -z "$1" ] && device="${REAL_ROOT}" || device="$1"
	[ -z "${device}" ] && return # LiveCD

	if [ `echo ${device}|sed -e 's#\(luks:\)\?\(/dev/md\)[[:digit:]]\+#\2#'` = "/dev/md" ]
	then
		good_msg 'Detected real_root as a md device. Setting up the device node...'
		MD_NUMBER=`echo ${device}|sed -e 's#\(luks:\)\?/dev/md\([[:digit:]]\+\)#\2#'`
		if [ ! -e /dev/md${MD_NUMBER} ]
		then
			mknod /dev/md${MD_NUMBER} b 9 ${MD_NUMBER} >/dev/null 2>&1
			[ $? -ne 0 ] && bad_msg "Creation of /dev/md${MD_NUMBER} failed..."
		fi
		mdstart ${MDPART} /dev/md${MD_NUMBER}
	fi
}

rundebugshell() {
	if [ -n "$DEBUG" ]
	then
		good_msg 'Starting debug shell as requested by "debug" option.'
		good_msg 'Type "exit" to continue with normal bootup.'
		[ -x /bin/sh ] && /bin/sh || /bin/ash
	fi
}

do_resume() {
	if [ -d /proc/suspend2 -o -d /sys/power/suspend2 -o -d /sys/power/tuxonice ]; then
		tuxonice_resume
	else
		swsusp_resume
	fi
}

swsusp_resume() {
	# determine swap resume partition
	local device=$(ls -lL "${REAL_RESUME}" | sed 's/\  */ /g' | cut -d \  -f 5-6 | sed 's/,\ */:/')
	[ -f /sys/power/resume ] && echo "${device}" > /sys/power/resume
}

tuxonice_resume() {
	local splash_theme
	if grep "splash=" /proc/cmdline > /dev/null 2>&1; then
		splash_theme=$(cat /proc/cmdline | sed 's/.*splash=/splash=/' | sed 's/ .*//' | sed 's/.*theme://' | sed 's/,.*//')
	fi

	local tuxonice_userui_program="/sys/power/tuxonice/user_interface/program"
	local tuxonice_do_resume="/sys/power/tuxonice/do_resume"
	local tuxonice_resumedev="/sys/power/tuxonice/resume"
	local tuxonice_replace_swsusp="/sys/power/tuxonice/replace_swsusp"

	#
	# Backward compatibility
	#
	if [ -e /sys/power/suspend2 ]; then
		tuxonice_userui_program="/sys/power/suspend2/user_interface/program"
		tuxonice_do_resume="/sys/power/suspend2/do_resume"
		tuxonice_resumedev="/sys/power/suspend2/resume"
		tuxonice_replace_swsusp="/sys/power/suspend2/replace_swsusp"
	elif [ -e /proc/suspend2 ]; then
		tuxonice_userui_program="/proc/suspend2/userui_program"
		tuxonice_do_resume="/proc/suspend2/do_resume"
		tuxonice_resumedev="/proc/suspend2/resume"
		tuxonice_replace_swsusp="/proc/suspend2/replace_swsusp"
	fi

	# if 'use_swsusp' is given, use swsusp instead
	if grep "use_swsusp" /proc/cmdline > /dev/null 2>&1; then
		echo 0 > ${tuxonice_replace_swsusp}
		swsusp_resume
		return
	fi

	modules_scan tuxonice

	# we both configure tuxonice and activate resuming,
	# however the kernel will resume only if an image is found

	if ! grep suspend_noui /proc/cmdline > /dev/null 2>&1; then
		which suspend2ui_text > /dev/null 2>&1 && which suspend2ui_text > "${tuxonice_userui_program}"
		which tuxoniceui_text > /dev/null 2>&1 && which tuxoniceui_text > "${tuxonice_userui_program}"

		if [ -n "${splash_theme}" ]; then
			ln -s /etc/splash/${splash_theme} /etc/splash/suspend2
			ln -s /etc/splash/${splash_theme} /etc/splash/tuxonice

			which suspend2ui_fbsplash > /dev/null 2>&1 && which suspend2ui_fbsplash > "${tuxonice_userui_program}"
			which tuxoniceui_fbsplash > /dev/null 2>&1 && which tuxoniceui_fbsplash > "${tuxonice_userui_program}"
		fi

	fi
	echo "${REAL_RESUME}" > "${tuxonice_resumedev}"
	echo > "${tuxonice_do_resume}"
}

find_loop() {
	CDROM="${NEW_ROOT}/mnt/cdrom"
	for loop in ${LOOPS}
	do
		if [ -e "${CDROM}""${loop}" ]
		then
			LOOP="${loop}"
		fi
	done
}

find_looptype() {
	LOOPTYPE="${LOOP##*.}"
	[ "${LOOPTYPE}" == "loop" ] && LOOPTYPE="normal"
	[ "${LOOP}" == "/zisofs" ] && LOOPTYPE="${LOOP#/}"
	[ -z "${LOOPTYPE}" ] && LOOPTYPE="noloop"
}

getdvhoff() {
	echo $(( $(hexdump -n 4 -s $((316 + 12 * $2)) -e '"%i"' $1) * 512))
}

setup_unionfs() {
	local rw_dir=$1
	local ro_dir=$2
	if [ "${USE_UNIONFS_NORMAL}" = '1' ]
	then
		# Directory used for rw changes in union mount filesystem
		UNION=/union
#		MEMORY=/memory
#		if [ -z "$UID" ]
#		then
#			CHANGES=$MEMORY/unionfs_changes/default
#		else
#			CHANGES=$MEMORY/unionfs_changes/$UID
#		fi

#		mkdir -p ${MEMORY}
		mkdir -p ${UNION}
		good_msg "Loading fuse module"
		modprobe fuse > /dev/null 2>&1
#                 if [ -n "${UNIONFS}" ] 	 
#                 then 	 
#                         CHANGESDEV=${UNIONFS} 	 
#                         good_msg "mounting $CHANGESDEV to $MEMORY for unionfs support" 	 
#                         mount -t auto $CHANGESDEV $MEMORY 	 
#                         # mount tmpfs only in the case when changes= boot parameter was 	 
#                         # empty or we were not able to mount the storage device 	 
#                         ret=$? 	 
#                         if [ ${ret} -ne 0 ]
#                         then 	 
#                                 bad_msg "mount of $CHANGESDEV failed falling back to ramdisk based unionfs" 	 
#                                 mount -t tmpfs tmpfs $MEMORY 	 
#                         fi 	 
#                         if [ "${CDROOT}" -eq '1' -a ! -f ${MEMORY}/livecd.unionfs  ] 	 
#                         then 	 
#                                 umount $MEMORY 	 
#                                 bad_msg "failed to find livecd.unionfs file on $CHANGESDEV" 	 
#                                 bad_msg "create a livecd.unionfs file on this device if you wish to use it for unionfs" 	 
#                                 bad_msg "falling back to ramdisk based unionfs for safety" 	 
#                                 mount -t tmpfs tmpfs $MEMORY 	 
#                         fi 	 
#                 else 	 
#                         good_msg "Mounting ramdisk to $MEMORY for unionfs support..." 	 
#                         mount -t tmpfs tmpfs $MEMORY 	 
#                 fi 	 
  	 
		mkdir /tmp
		mkdir -p ${UNION}
#		mkdir -p $CHANGES
#		mount -t unionfs -o dirs=$CHANGES=rw unionfs ${UNION}
		good_msg "Creating union mount"
		unionfs -o allow_other,cow,noinitgroups,suid,dev,default_permissions,use_ino ${rw_dir}=RW:${ro_dir}=RO ${UNION} 2>/dev/null
		ret=$?
		if [ ${ret} -ne 0 ]
		then
			bad_msg "Can't setup union mount!"
			USE_UNIONFS_NORMAL=0
		fi
	else
		USE_UNIONFS_NORMAL=0
	fi
}
